home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / zm16src / expandar.c < prev    next >
C/C++ Source or Header  |  1988-05-18  |  15KB  |  701 lines

  1.  
  2.     /* 
  3.      *     Examine each argument given to expandargs()
  4.      *     If it is a directory, then expand it
  5.      *    to all its component files, recursively
  6.      *    till you bottom out.
  7.      *    If it is not a directory, then just pass it on.
  8.      *
  9.      *    Inputs: routine, argc, argv
  10.      *    Outputs: nargc, nargv (calls routine(nargc, nargv))
  11.      *    To test: compile with -DTEST
  12.      *         define MWC if using Mark Williams C
  13.      *         run with a directory as an arg
  14.      *    Author: JRB    bammi@mandrill.ces.CWRU.edu
  15.      *    Requirements: Mark Williams C or Alcyon C
  16.      *        Wants lots of Dynamic memory. It
  17.      *        all depends upon how many files you
  18.      *        have. Use the -P option to prune
  19.      *        out subdirectories and do things
  20.      *        one at a time, if you keep running
  21.      *        out of memory.
  22.      *        With Mark Williams i use _stksize = 128K
  23.      *        With Alcyon i use memory model 2 (half of
  24.      *        of avail memory) in GEMSTART.S
  25.      *
  26.          *      WARNINGS: Be CAREFUL about the 40 folder bug. Use
  27.      *              GEMBOOT or FOLDRXXX when dealing with
  28.      *          a deeply nested file structure.
  29.      *
  30.      *    Added -P name prune option at the suggestion of dietz@zhmti
  31.      *    Multiple -P's may be given on the command line.
  32.      *    -P name may be given anywhere on the command line. -P name
  33.      *    will prune the subdirectories named as arguement to -P.
  34.      *    ie: when the program is decending the file hierarchy it
  35.      *    will not visit the pruned branches.
  36.      *     NOTE that the option is -P and not -p
  37.      *          (-p is a valid sz option).
  38.      *    NOTE that the arguement given to -P can be the name
  39.      *     of a file or a directory. In case it is a file,
  40.      *    that file is skipped.
  41.      *
  42.      */
  43.  
  44. /*
  45.  * Expand argc, so that the called routine(nargc,nargv) receives only
  46.  * filenames, in nargv[][]
  47.  *
  48.  ************************************************************************
  49.  *                                    *
  50.  *      WARNING:  Be CAREFUL about the 40 folder bug. Use        *
  51.  *              GEMBOOT or FOLDRXXX when dealing with            *
  52.  *          a deeply nested file structure.            *
  53.  *                                    *
  54.  ************************************************************************
  55.  *
  56.  *    Jwahar R. Bammi
  57.  *            usenet: mandrill!bammi@{decvax,sun}.UUCP
  58.  *            csnet:  bammi@mandrill.ces.CWRU.edu
  59.  *            arpa:   bammi@mandrill.ces.CWRU.edu
  60.  *            CompuServe: 71515,155
  61.  *
  62.  */
  63.  
  64. #ifdef TEST
  65. #include <stdio.h>
  66. #include <osbind.h>
  67. #include <ctype.h>
  68. #endif
  69.  
  70. #ifdef TRUE
  71. #undef TRUE
  72. #endif
  73. #ifdef OK
  74. #undef OK
  75. #endif
  76. #ifdef FALSE
  77. #undef FALSE
  78. #endif
  79.  
  80. #define TRUE     1
  81. #define OK     0
  82. #define FALSE     0
  83. #define Realloc     realloc
  84.  
  85. #ifdef TEST
  86. struct    stat
  87. {
  88.     char    st_sp1[21];    /* Junk        */
  89.     char    st_mode;       /* File attributes */
  90.     int    st_time;       /* Mod Time      */
  91.     int     st_date;       /* Mod date      */
  92.     long    st_size;       /* File size       */
  93.     char    st_name[14];   /* File name       */
  94. };
  95. #endif
  96.  
  97. typedef struct _prunelist {
  98.     char *name;            /* name of subdirectory to prune */
  99.     struct _prunelist *next;    /* ptr to next */
  100. } PRUNELIST;
  101.  
  102. static char *ProgName;
  103. static PRUNELIST *PruneList = (PRUNELIST *)NULL; /* Head of PruneList */
  104.  
  105. static char **CopyToNargv();
  106. static char **ExpandStack();
  107. static void FreeStack();
  108. static void FreeNargv();
  109. static void FreePrune();
  110. static void FreeUp();
  111. static int PushDir();
  112. static char *PopDir();
  113. static int ProcessDirs();
  114. static PRUNELIST *AddPrune();
  115. static int OnPruneList();
  116. static int isdir();
  117.  
  118. extern int existd();
  119.  
  120. expandargs(routine, argc, argv)
  121. int (*routine)();
  122. int argc;
  123. char **argv;
  124. {
  125.     register int status;
  126.     int nargc;
  127.     char **nargv;
  128.     extern char **CopyToNargv();
  129.     extern PRUNELIST *AddPrune();
  130.     extern int existd();
  131.  
  132.     nargc = 0;
  133.     nargv = (char **)NULL;
  134.     ProgName = *argv;
  135.     
  136.     /* copy argv[0] blindly */
  137.     if((nargv = CopyToNargv(*argv, nargc, nargv)) == (char **)NULL)
  138.     {
  139.         FreeUp(nargc, nargv);
  140.         return(~OK);
  141.     }
  142.  
  143.     nargc++;
  144.     
  145.     while((--argc) > 0)
  146.     {
  147.         argv++;
  148.         if(**argv == '-')
  149.         {
  150.             /* copy any options except -P */
  151. #ifdef TEST
  152.             /* some shell pass -P as -p */
  153.             if( ((*argv)[1] == 'P') || ((*argv)[1] == 'p'))
  154. #else
  155.             if( (*argv)[1] == 'P')
  156. #endif
  157.             {
  158.                 if((--argc) <= 0)
  159.                 {
  160.                     fprintf(STDERR,"no argument given to -P\n");
  161.                     FreeUp(nargc, nargv);
  162.                     return(~OK);
  163.                 }
  164.                 if((PruneList = AddPrune(PruneList,*++argv))
  165.                    == (PRUNELIST *)NULL)
  166.                 {
  167.                     FreeUp(nargc, nargv);
  168.                     return(~OK);
  169.                 }
  170.             }
  171.             else
  172.             {
  173.                 if((nargv = CopyToNargv(*argv, nargc, nargv))
  174.                    == (char **)NULL)
  175.                 {
  176.                     FreeUp(nargc, nargv);
  177.                     return(~OK);
  178.                 }
  179.                 else
  180.                     nargc++;
  181.             }
  182.             
  183.         }
  184.         else
  185.         {
  186.             /* If its not on the PruneList then */
  187.             if(!OnPruneList(PruneList, *argv))
  188.             {
  189.                 /* if it is a directory, push it */
  190.                 if(existd(*argv))
  191.                 {
  192.                     if((status = PushDir(*argv)) != OK)
  193.                     {
  194.                         FreeUp(nargc, nargv);
  195.                         return(status);
  196.                     }
  197.                 }
  198.                 else
  199.                 {
  200.                     /* it is NOT a directory, copy to nargv */
  201.                     if((nargv = CopyToNargv(*argv, nargc, nargv))
  202.                        == (char **)NULL)
  203.                     {
  204.                         FreeUp(nargc, nargv);
  205.                         return(~OK);
  206.                     }
  207.                     else
  208.                         nargc++;
  209.                 }
  210.             }
  211.         }
  212.     } /* while */
  213.  
  214.     /* process pushed directories if any */
  215.     if((status = ProcessDirs(&nargc, &nargv)) != OK)
  216.     {
  217.         FreeUp(nargc, nargv);
  218.         return(status);
  219.     }
  220.     /* else Free the Stack and Prune List, call *routine */
  221.     FreeStack();
  222.     FreePrune();
  223.     status =  (*routine)(nargc, nargv);
  224.     FreeNargv(nargc, nargv);
  225.  
  226.     return status;
  227.  
  228. }
  229.  
  230. /*
  231.  * Expand nargv by an element and copy a String into the new element
  232.  *
  233.  */
  234. static char **CopyToNargv(string, nargc, nargv)
  235. char *string;
  236. int nargc;
  237. char **nargv;
  238. {
  239.     extern char *malloc(), *Realloc(), *strcpy();
  240.     extern int strlen();
  241.     
  242.     /* expand nargv by 1 element */
  243.     if(nargv == (char **)NULL)
  244.         /* do it with malloc for the first one */
  245.         nargv = (char **)malloc(sizeof(char **));
  246.     else
  247.         /* do it with Realloc for others */
  248.         nargv = (char **)Realloc(nargv, (nargc+1)*sizeof(char **));
  249.     
  250.     if(nargv == (char **)NULL)
  251.     {
  252.         /* failed to get memory */
  253.         fprintf(STDERR,"%s(CopyToNargv()): Out of Memory\n", ProgName);
  254.         return ((char **)NULL);
  255.     }
  256.  
  257.     /* Get mem for string */
  258.     if(( nargv[nargc] = malloc(strlen(string)+1)) == (char *)NULL)
  259.     {
  260.         /* failed to get memory */
  261.         fprintf(STDERR,"%s(CopyToNargv()): Out of Memory\n", ProgName);
  262.         return ((char **)NULL);
  263.     }
  264.  
  265.     /* copy string into nargv[nargc] */
  266.     (void)strcpy( nargv[nargc], string);
  267.     return(nargv);
  268. }
  269.  
  270. static char **Stack = (char **)NULL;    /* directory stack */
  271. static char StackSize = 0;        /* Size of current Stack */
  272. static int    Top   = -1;
  273. #define STACK_EMPTY    (Top < 0)
  274. #define CHUNKSIZE    16
  275.  
  276. /*
  277.  * Grow the Stack by one chunk of CHUNKSIZE elements
  278.  *
  279.  */
  280. static char **ExpandStack(Stack)
  281. char **Stack;
  282. {
  283.     extern char *malloc(), *Realloc();
  284.     
  285.     /* Grow Stack */
  286.     if(Stack == (char **)NULL)
  287.         /* with malloc */
  288.         Stack = (char **)malloc(CHUNKSIZE * sizeof(char **));
  289.     else
  290.         /* with Realloc */
  291.         Stack = (char **)Realloc(Stack, (StackSize+CHUNKSIZE) *
  292.                              sizeof(char **));
  293.  
  294.     if(Stack == (char **)NULL)
  295.     {
  296.         /* outa mem */
  297.         fprintf(STDERR,"%s(ExpandStack()): Out of Memory\n", ProgName);
  298.         return((char **)NULL);
  299.     }
  300.     StackSize += CHUNKSIZE;
  301.     return(Stack);
  302. }
  303.  
  304. /*
  305.  * Free the Stack
  306.  *
  307.  */
  308. static void FreeStack()
  309. {
  310.     if(StackSize > 0)
  311.         (void)free(Stack);
  312.     Stack = (char **)NULL;
  313.     StackSize = 0;
  314.     Top   = -1;
  315. }
  316.  
  317. /*
  318.  * Free Nargv
  319.  *
  320.  */
  321. static void FreeNargv(nargc, nargv)
  322. int nargc;
  323. char *nargv[];
  324. {
  325.     register int i;
  326.  
  327.     for(i = 0; i < nargc; i++)
  328.         (void)free(nargv[i]);
  329.     if(nargc > 0)
  330.         (void)free(nargv);
  331. }
  332.  
  333. /*
  334.  * Free the PruneList
  335.  *
  336.  */
  337. static void FreePrune()
  338. {
  339.     register PRUNELIST *p, *next;
  340.  
  341.     for(p = PruneList; p != (PRUNELIST *)NULL; p = next)
  342.     {
  343.         next = p->next;
  344.         (void)free(p);
  345.     }
  346.     PruneList = (PRUNELIST *)NULL;
  347. }
  348.  
  349. /*
  350.  * FreeUp before bad exit
  351.  *
  352.  */
  353. static void FreeUp(nargc, nargv)
  354. int nargc;
  355. char **nargv;
  356. {
  357.     FreeStack();
  358.     FreePrune();
  359.     FreeNargv(nargc, nargv);
  360. }
  361.  
  362. /*
  363.  * Push a directory name on Stack
  364.  *
  365.  */
  366. static int PushDir(name)
  367. char *name;
  368. {
  369.     extern char *malloc(), *strcpy();
  370.     extern int strlen();
  371.     extern char **ExpandStack();
  372.  
  373. #ifdef DDEBUG
  374. printf("PushDir: %s\n", name);
  375. #endif
  376.  
  377.     ++Top;
  378.     if(Top >= StackSize)
  379.     {
  380.         if((Stack = ExpandStack(Stack)) == (char **)NULL)
  381.             return(~OK);
  382.     }
  383.     
  384.     if((Stack[Top] = malloc(strlen(name)+1)) == (char *)NULL)
  385.     {
  386.         /* outa mem */
  387.         fprintf(STDERR,"%s(PushDir()): Out of Memory\n", ProgName);
  388.         return(~OK);
  389.     }
  390.     (void)strcpy(Stack[Top], name);
  391.     return(OK);
  392. }
  393.  
  394. /*
  395.  * Pop a directory name from the stack
  396.  *
  397.  */
  398. static char *PopDir()
  399. {
  400.     register char *r;
  401.     extern char **ShrinkStack();
  402.     
  403.     if(STACK_EMPTY)
  404.         return ((char *)NULL);
  405.     
  406.     r = Stack[Top];
  407.     Top--;
  408.     return(r);
  409. }
  410.  
  411. static int BadStatus = FALSE;
  412. #define BADSTATUS (BadStatus != FALSE)
  413. #define MAXNAMLEN 128
  414.  
  415. /*
  416.  * Process directories on the Stack, by adding all the
  417.  * files in a directory to nargv.
  418.  */
  419. static int ProcessDirs(nargc, nargv)
  420. int *nargc;
  421. char ***nargv;
  422. {
  423.     register char *name;
  424.     register struct stat *dp;
  425.     register int status, slashp;
  426.     char path[MAXNAMLEN+1];
  427.     extern char **CopyToNargv();
  428.     extern char *PopDir();
  429.     extern char *alltolower();
  430.     
  431.     if(BADSTATUS)
  432.         return(~OK);
  433.  
  434.     if(STACK_EMPTY)
  435.         /* Nothing more to do */
  436.         return(OK);
  437.  
  438.     /* Pop a directory from Stack and process */
  439.     if((name = PopDir()) == (char *)NULL)
  440.     {
  441.         /* Oh Oh */
  442.         fprintf(STDERR,"Internal Error (BUG), PopDir returns NULL\n");
  443.         BadStatus = (~FALSE);
  444.         return(~OK);
  445.     }
  446.     
  447.     strcpy(path, name);
  448.     if(path[(strlen(path)-1)] == '\\')
  449.     {
  450.         strcat(path,"*.*");
  451.         slashp = TRUE;
  452.     }
  453.     else
  454.     {
  455.         strcat(path,"\\*.*");
  456.         slashp = FALSE;
  457.     }
  458.         
  459.     /* Open the directory */
  460.     if(Fsfirst(path, 0x0020| 0x0010 | 0x0001) != 0)
  461.     {
  462.         /* trouble opening directory */
  463.         fprintf(STDERR,"Trouble opening %s\n",path);
  464.         /* set BADSTATUS and return */
  465.         BadStatus = (~FALSE);
  466.         return(~OK);
  467.     }
  468.  
  469.     /* get the DTA */
  470.     dp = (struct stat *)Fgetdta();
  471.     
  472.     /* for each entry in the directory, if it is a file
  473.        add to nargv. If it is a directory, Push it onto
  474.        the directory stack.
  475.      */
  476.     do
  477.     {
  478.         if(! ((strcmp(dp->st_name,".") == 0) ||
  479.               (strcmp(dp->st_name,"..") == 0)) )
  480.         {
  481.             strcpy(path, name);
  482.             if(!slashp)
  483.                 strcat(path,"\\");
  484.             strcat(path,dp->st_name);
  485.  
  486.             /* If this path is on the PruneList skip */
  487.             if(OnPruneList(PruneList, alltolower(path)))
  488.                 continue;
  489.  
  490.             if(!isdir(path, dp->st_mode))
  491.             {
  492.                 /* not a dir -- add this to nargv */
  493.                 if((*nargv = CopyToNargv(path, *nargc, *nargv))
  494.                     == (char **)NULL)
  495.                 {
  496.                     BadStatus = (~FALSE);
  497.                     return(~OK);
  498.                 }
  499.                 else
  500.                 {
  501.                     *nargc += 1;
  502.                 }
  503.                 
  504.             }
  505.             else
  506.             {
  507.  
  508.                 /* Push This directory */
  509.                 if((status = PushDir(path)) != OK)
  510.                 {
  511.                     BadStatus = (~FALSE);
  512.                     return(status);
  513.                 }
  514.             }
  515.         }
  516.     } while(Fsnext() == 0);
  517.  
  518.     free(name);    /* done with this directory */
  519.     
  520.     /* go do the rest */
  521.     return (ProcessDirs(nargc, nargv));
  522. }
  523.  
  524. /*
  525.  * Add a name to PruneList
  526.  *
  527.  */
  528. static PRUNELIST *AddPrune(list, name)
  529. PRUNELIST *list;
  530. char *name;
  531. {
  532.     extern char *malloc();
  533.     register PRUNELIST *new;
  534.     
  535.     if((new = (PRUNELIST *)malloc(sizeof(PRUNELIST))) == (PRUNELIST *)NULL)
  536.     {
  537.         /* outa mem */
  538.         fprintf(STDERR,"%s(AddPrune()): Out of Memory\n", ProgName);
  539.         return(new);
  540.     }
  541.  
  542.     new->name = name;
  543.     new->next = list;
  544.     
  545.     return(new);
  546. }
  547.  
  548. /*
  549.  * Search for name on PruneList
  550.  *
  551.  */
  552. static int OnPruneList(list, name)
  553. register PRUNELIST *list;
  554. register char *name;        
  555. {
  556.     for(; list != (PRUNELIST *)NULL; list = list->next)
  557.     {
  558.         if(strcmp(list->name, name) == 0)
  559.             return(~FALSE);
  560.     }
  561.     
  562.     return(FALSE);
  563. }
  564.  
  565. /*
  566.  * test if a subdirectory exists, without touching the DTA
  567.  * include special case of 'D:\' that Fsfirst does'nt handle correctly
  568.  */
  569. static int isdir(name, attr)
  570. register char *name;
  571. register int attr;
  572. {
  573.     /* assuming the DTA buffer is already set up */
  574.     extern long drv_map;
  575.     register int drive;
  576.     
  577.     if(attr & 0x0010)
  578.         return TRUE;
  579.  
  580.     /* Gemdos doesn't like d:\ style dirs */
  581.     if((name[3] == '\0') && (name[2] == '\\') && (name[1] == ':'))
  582.     {
  583.         drive = name[0];
  584.         if(isupper(drive))
  585.             drive = tolower(drive);
  586.  
  587.         drive = drive - 'a';
  588.         if((drv_map & (1L << drive)) == 0)
  589.             return FALSE;
  590.         else
  591.             return TRUE;
  592.     }
  593.     /* Nor does Gemdos understand '.' or '..' */
  594.     /* Hey Atari, don't you guys ever test anything */
  595.     if((strcmp(name,".") == 0) || (strcmp(name,"..") == 0) ||
  596.        (strcmp(name,".\\") == 0) || (strcmp(name,"..\\") == 0))
  597.         return TRUE;
  598.  
  599.     return FALSE;
  600. }
  601.  
  602.  
  603. #ifdef TEST
  604.  
  605. /*
  606.  * convert string to all lower case
  607.  */
  608. char *alltolower(s)
  609. char *s;
  610. {
  611.     register char *p;
  612.  
  613.     for(p = s; *p != '\0'; p++)
  614.         if(isupper(*p))
  615.             *p = tolower(*p);
  616.  
  617.     return s;
  618. }
  619.     
  620. /*
  621.  * test if a subdirectory exists
  622.  * include special case of 'D:\' that Fsfirst does'nt handle correctly
  623.  * (this routine not needed for zmdm, as it is defined in common.c)
  624.  */
  625. int existd(name)
  626. register char *name;
  627. {
  628.     /* assuming the DTA buffer is already set up */
  629.     /* assumes drv_map has been read in drv_map externally */
  630.     extern long drv_map;
  631.     register int drive;
  632.     extern struct stat statbuf;
  633.     
  634.     if (Fsfirst(name , 0x0021|0x0010) == 0)
  635.     {
  636.         if((statbuf.st_mode & 0x0010) == 0x0010)
  637.             return TRUE;
  638.     }
  639.  
  640.     /* Gemdos doesn't like d:\ style dirs */
  641.     if((name[3] == '\0') && (name[2] == '\\') && (name[1] == ':'))
  642.     {
  643.         drive = name[0];
  644.         if(isupper(drive))
  645.             drive = tolower(drive);
  646.  
  647.         drive = drive - 'a';
  648.         if((drv_map & (1L << drive)) == 0)
  649.             return FALSE;
  650.         else
  651.             return TRUE;
  652.     }
  653.     /* Nor does Gemdos understand '.' or '..' */
  654.     /* Hey Atari, don't you guys ever test anything */
  655.     if((strcmp(name,".") == 0) || (strcmp(name,"..") == 0) ||
  656.        (strcmp(name,".\\") == 0) || (strcmp(name,"..\\") == 0))
  657.         return TRUE;
  658.  
  659.     return FALSE;
  660. }
  661.  
  662. int MAIN(argc, argv)
  663. int argc;
  664. char **argv;
  665. {
  666.     register int i;
  667.     
  668.     for(i = 0; i < argc; i++)
  669.         printf("%d:\t%s\n", i, argv[i]);
  670.  
  671.  
  672.     return(0);
  673. }
  674.  
  675.  
  676. struct stat statbuf;      /* Disk Transfer address for Find first etc */
  677. long drv_map;
  678.  
  679. #ifdef MWC
  680. long _stksize = 128L * 1024L;
  681. #endif
  682.  
  683. #ifdef MANX
  684. long _STKSIZ = 128L * 1024L;
  685. #endif
  686.  
  687. main(argc, argv)
  688. int argc;
  689. char **argv;
  690. {
  691.     /* Set up Dta */
  692.     Fsetdta(&statbuf);
  693.     drv_map = Drvmap();
  694.  
  695.     exit(expandargs(MAIN, argc, argv));
  696. }
  697.  
  698. #endif /* TEST */
  699.  
  700. /* -eof- */
  701.